/*-----------------------------------------------------------------------------
 * @file   utils_str.c
 * @brief  utils for string operation
 * @author WLH<wanglehui8357@163.com> Copyright (C) 2021~2099.
 ----------------------------------------------------------------------------*/
#include "utils_str.h"
#include "ascii.h"

/*-----------------------------------------------------------------------------
 * Macro define
-----------------------------------------------------------------------------*/
#define STR_LEN_MAX 255u

/*-----------------------------------------------------------------------------
 * Local variable
-----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
 * public functions
-----------------------------------------------------------------------------*/
int str_util_cmp(const char* str1, const char* str2, const bool ignore_case)
{
    int cmp_val;

    if (!ignore_case)
    {
        return strcmp(str1, str2);
    }
    if (NULL == str1)
    {
        return NULL == str2 ? 0 : -1;
    }
    if (NULL == str2)
    {
        return NULL == str1 ? 0 : 1;
    }

    const char* str1_cmp = str1;
    const char* str2_cmp = str2;
    const char* str1_cmp_next = str1_cmp;
    const char* str2_cmp_next = str2_cmp;
    str1_cmp_next++;
    str2_cmp_next++;

    char char_1 = TO_LOWER(*str1_cmp);
    char char_2 = TO_LOWER(*str2_cmp);
    int cmp_len = 0u;

    while ((char_1 == char_2) &&                /* Cmp strs until non-matching chars (see Note #3c) ... */
           (*str1_cmp != (char)'\0') &&         /* ... or NULL chars                 (see Note #3b) ... */
           (str1_cmp_next != (const char*)0) && /* ... or NULL ptr(s) found          (see Note #3a2).   */
           (str2_cmp_next != (const char*)0) &&
           (cmp_len < STR_LEN_MAX))
    { /* ... or max nbr chars cmp'd        (see Note #3d2).   */
        str1_cmp++;
        str2_cmp++;
        str1_cmp_next++;
        str2_cmp_next++;
        cmp_len++;
        char_1 = TO_LOWER(*str1_cmp);
        char_2 = TO_LOWER(*str2_cmp);
    }

    if (cmp_len == STR_LEN_MAX)
    { /* If strs identical for max len nbr of chars, ...  */
        return 0;
    }

    if (char_1 != char_2)
    { /* If strs NOT identical, ...                           */
        /* ... calculate & rtn char diff  (see Note #3c1).           */
        cmp_val = ((int)char_1 - (int)char_2);
    }
    else if (char_1 == (char)'\0')
    {                /* If NULL char(s) found, ... */
        cmp_val = 0; /* ... strs identical; rtn 0 (see Note #3b). */
    }
    else
    {
        if (str1_cmp_next == (const char*)0)
        {
            if (str2_cmp_next == (const char*)0)
            {                /* If BOTH next str ptrs NULL, ...                      */
                cmp_val = 0; /* ... rtn 0     (see Note #3a2A).    */
            }
            else
            { /* If str1_cmp_next NULL, ...                         */
                char_2 = TO_LOWER(*str2_cmp_next);
                /* ... rtn neg str2_cmp_next val (see Note #3a2B1).   */
                cmp_val = (0 - (int)char_2);
            }
        }
        else
        {                          /* If str2_cmp_next NULL, ...                         */
            char_1 = TO_LOWER(*str1_cmp_next);
            cmp_val = (int)char_1; /* ... rtn pos str1_cmp_next val (see Note #3a2B2).   */
        }
    }

    return cmp_val;
}

bool str_util_is_equal(const char* str1, const char* str2, const size_t len)
{
    for (unsigned i = 0u; i < len; i++)
    {
        if (str1[i] != str2[i])
        {
            return false;
        }
    }

    return true;
}

int str_util_index(const char* pstr, const char c, const size_t cnt)
{
    assert(cnt < STR_LEN_MAX);
    if (cnt >= STR_LEN_MAX)
    {
        return -1;
    }

    for (unsigned i = 0u; i < cnt; i++)
    {
        if (c == pstr[i])
        {
            return i;
        }
    }
    return -1;
}

bool str_util_is_digital(const char* pstr, const size_t cnt)
{
    bool re = true;
    assert(cnt < STR_LEN_MAX);
    if (cnt >= STR_LEN_MAX)
    {
        return false;
    }

    for (unsigned i = 0u; i < cnt; i++)
    {
        if (!IS_DIGITAL(pstr[i]))
        {
            re = false;
            break;
        }
    }
    return re;
}

U32 str_util_hash(const char* pstr, const size_t cnt)
{
    U32 b = 378551U;
    U32 a = 63689U;
    U32 hash = 0U;
    for (unsigned i = 0u; i < cnt; i++)
    {
        hash = hash * a + pstr[i];
        a *= b;
    }
    return (hash & 0x7FFFFFFFU);
}

U8 str_util_len(const char* pstr)
{
    for (U8 i= 0u; i < STR_LEN_MAX; i++)
    {
        if(pstr[i] == '\0') return i;
    }

    return 0xFFu;
}